1 module hip.hipaudio.backend.openal.player; 2 version(OpenAL): 3 import hip.hipaudio.backend.openal.clip; 4 import hip.hipaudio.backend.openal.source; 5 import hip.hipaudio.backend.openal.al_err; 6 import hip.hipaudio.audio; 7 import hip.error.handler; 8 import hip.audio_decoding.audio; 9 import hip.math.vector; 10 import bindbc.openal; 11 12 13 package ALenum getFormatAsOpenAL(AudioConfig cfg) 14 { 15 if(cfg.channels == 1) 16 { 17 if(cfg.format == AudioFormat.float32Big || cfg.format == AudioFormat.float32Little) 18 return AL_FORMAT_MONO_FLOAT32; 19 else if(cfg.format == AudioFormat.signed16Little || cfg.format == AudioFormat.signed16Big) 20 return AL_FORMAT_MONO16; 21 else 22 return AL_FORMAT_MONO8; 23 } 24 else 25 { 26 if(cfg.format == AudioFormat.float32Big || cfg.format == AudioFormat.float32Little) 27 return AL_FORMAT_STEREO_FLOAT32; 28 else if(cfg.format == AudioFormat.signed16Little || cfg.format == AudioFormat.signed16Big) 29 return AL_FORMAT_STEREO16; 30 else 31 return AL_FORMAT_STEREO8; 32 } 33 } 34 35 36 37 /** 38 * Wraps OpenAL API onto the IAudioPlayer interface. With that, when HipAudioSourceAPI receives that interface, 39 * it will update OpenAL properties through that interface. 40 */ 41 public class HipOpenALAudioPlayer : IHipAudioPlayer 42 { 43 public this(AudioConfig cfg) 44 { 45 initializeOpenAL(); 46 config = cfg; 47 } 48 public static bool initializeOpenAL() 49 { 50 ErrorHandler.startListeningForErrors("HipremeAudio3D initialization"); 51 version(BindOpenAL_Static){} 52 else 53 { 54 ALSupport sup = loadOpenAL(); 55 if(sup != ALSupport.al11) //Probably should not load a non al11 version. 56 { 57 if(sup == ALSupport.badLibrary) 58 ErrorHandler.showErrorMessage("Bad OpenAL Support", "Unknown version of OpenAL"); 59 else 60 { 61 ErrorHandler.showErrorMessage("OpenAL not found", "Could not find OpenAL library"); 62 return false; 63 } 64 } 65 } 66 device = alcOpenDevice(alcGetString(null, ALC_DEVICE_SPECIFIER)); 67 if(device == null) 68 { 69 ErrorHandler.showErrorMessage("OpenAL Initialization", "Error on creating device"); 70 return false; 71 } 72 //static const ALCint* contextAttr = [ALC_FREQUENCY, 22_050, 0]; 73 context = alcCreateContext(device, null); 74 if(context == null) 75 { 76 ErrorHandler.showErrorMessage("OpenAL context error", "Error creating OpenAL context"); 77 return false; 78 } 79 if(!alcMakeContextCurrent(context)) 80 ErrorHandler.showErrorMessage("OpenAL context error", "Error setting context"); 81 82 //Set Listener 83 84 alListener3f(AL_POSITION, 0f, 0f, 0f); 85 alListener3f(AL_VELOCITY, 0f, 0f, 0f); 86 87 version(BindOpenAL_Static) 88 { 89 if(&alEffecti is null) 90 ErrorHandler.showErrorMessage("OpenAL EFX Error", "Could not load OpenAL EFX"); 91 } 92 else 93 { 94 if(!alEffecti) 95 ErrorHandler.showErrorMessage("OpenAL EFX Error", "Could not load OpenAL EFX"); 96 } 97 98 return ErrorHandler.stopListeningForErrors(); 99 } 100 public AHipAudioSource getSource(bool isStreamed = false){return new HipOpenALAudioSource(isStreamed);} 101 102 public bool play_streamed(AHipAudioSource src) 103 { 104 HipOpenALAudioSource source = cast(HipOpenALAudioSource)src; 105 HipOpenALClip _buf = cast(HipOpenALClip)source.clip; 106 if(_buf.hasBuffer) 107 { 108 alSourcePlay(source.id); 109 alCheckError("Error querying OpenAL play streamed"); 110 return true; 111 } 112 return false; 113 } 114 115 public HipAudioClipAPI getClip(){return new HipOpenALClip(new HipAudioDecoder(), getClipHint());} 116 117 public HipAudioClipAPI loadStreamed(string path, uint chunkSize) 118 { 119 HipAudioClipAPI clip = new HipOpenALClip(new HipAudioDecoder(), getClipHint(), chunkSize); 120 // clip.loadStreamed(path, getEncodingFromName(path)); 121 return clip; 122 } 123 124 public void updateStream(AHipAudioSource source) 125 { 126 // HipOpenALAudioSource src = cast(HipOpenALAudioSource)source; 127 // HipOpenALClip clip = cast(HipOpenALClip)src.buffer; 128 // ALuint b = clip.getALBuffer(); 129 // alSourceQueueBuffers(src.id, 1, &b); 130 // alCheckError("Error enqueueing OpenAL buffer on source")); 131 } 132 133 134 //End Effects 135 public void onDestroy() 136 { 137 alcDestroyContext(context); 138 alcCloseDevice(device); 139 context = null; 140 device = null; 141 } 142 143 public void update() 144 { 145 146 } 147 148 /** 149 * OpenAL has an embedded resampler 150 */ 151 protected static HipAudioClipHint getClipHint() 152 { 153 HipAudioClipHint hint = { 154 outputChannels: HipOpenALAudioPlayer.config.channels, 155 outputSamplerate: HipOpenALAudioPlayer.config.sampleRate, 156 needsResample: false, 157 needsDecode: true 158 }; 159 return hint; 160 } 161 162 package __gshared AudioConfig config; 163 protected __gshared ALCdevice* device; 164 protected __gshared ALCcontext* context; 165 166 /** 167 * Constant used for making the panning distance offset from the listener 168 */ 169 public __gshared ALfloat PANNING_CONSTANT = 1000; 170 }